/**
 * \file    action.h
 * \brief   Parser generator.
 * \author  Jérôme LAURENS
 * \version 0.1
 * \date    September 23, 2014
 *
 * Reads a LALR(1) grammar, generates a parser based on a template file.
 * This is based on lemon parser generator, but has strongly been
 * revisited.
 *
 */

#ifndef ACTION_H
#define ACTION_H

#include "common.h"
#include "symbol.h"

LPP_NAMESPACE_BEGIN

class Action {
public:
    enum Type {
        SHIFT = 1,
        REDUCE = 2,
        ERROR = 3,
        OTHER = 4,                  /* Deleted by compression */
        MASK = 0xFF,
        RESOLVED_ = MASK+1,
        SH_RESOLVED = SHIFT+RESOLVED_, /* Was a shift.  Precedence resolved conflict */
        RD_RESOLVED = REDUCE+RESOLVED_,/* Was reduce.   Precedence resolved conflict */
        S_CONFLICT = RESOLVED_<<1,
        R_CONFLICT = S_CONFLICT<<1,
        SSCONFLICT = SHIFT+S_CONFLICT, /* A shift/shift conflict */
        SRCONFLICT = REDUCE+S_CONFLICT,/* Was a reduce, but part of a conflict */
        RRCONFLICT = REDUCE+R_CONFLICT,/* Was a reduce, but part of a conflict */
    };
    SymbolRef const & lookahead() const {/*! The look-ahead symbol */
        return lookahead_m;
    }
public:
    Index lookahead_index() const { /*! The look-ahead symbol */
        return lookahead_m->index();
    }
    Type type() const {
        return type_m;
    }
    void type(Type const type) {
        if (type_m != type) {
            type_m = type;
            std::cout<<"Type did change: "<<Description()(*this)<<std::endl;
        }
    }
    String description(String::size_type indent = 0
            , bool showPrecedenceConflicts = false) const;

    Action(SymbolRef const & __sym, StateRef const &__stt)
        : lookahead_m(__sym)
        , type_m(SHIFT)
        , x(__stt) {};
    Action(SymbolRef const & __sym, RuleRef const & __r)
        : lookahead_m(__sym)
        , type_m(REDUCE)
        , x(__r) {};
    Action(Type const __t, SymbolRef const & __sym)
        : lookahead_m(__sym)
        , type_m(__t)
        , x(false) {};
    static ActionRef const Make(Type const __t, SymbolRef const & __sym) {
        return std::make_shared<Action>(__t,__sym);
    }
    Action(Action const & action)
        : lookahead_m(action.lookahead_m)
        , type_m(action.type_m)
        , x(action.x) {};

    bool is_shift() const {
        return (type_m&MASK)==SHIFT;
    }
    StateRef const shift_state() const {
        return boost::get<StateWRef>(x).lock();
    }
    bool is_reduce() const {
        return (type_m&MASK)==REDUCE;
    }
    RuleRef const & reduce_rule() const {
        return boost::get<RuleRef>(x);
    }
    bool is_error() const {
        return (type_m&MASK)==ERROR;
    }
    bool is_terminal() const {
        return lookahead_m->is_terminal();
    }
    bool is_non_terminal() const {
        return lookahead_m->is_non_terminal();
    }
#warning THIS IS NOT USED
    bool is_default() const {
        return lookahead_m->is_default();
    }
    void set_default();

    void set_not_used() {
    }
    ActionCode pre_code() const;
#ifndef LPP_NO_DEFAULT_ACTIONS
    bool use_default() const {
        return use_default_m;
    }
    void use_default(bool yorn) {
        use_default_m = yorn;
    }
    bool can_default() const {
        return is_shift()||is_reduce();
    }
#endif

private:
    SymbolRef lookahead_m;
    Type type_m;
    typedef boost::variant<StateWRef,RuleRef,bool> StateOrRuleRef;// bool is not used, tricky for a default initialization
    StateOrRuleRef x;
#ifndef LPP_NO_DEFAULT_ACTIONS
    bool use_default_m;
#endif
};

int compare(
        Action const & ap1,
        Action const & ap2
       ) ;
bool operator == (
        Action const & ap1,
        Action const & ap2
       ) ;
bool operator < (
        Action const & ap1,
        Action const & ap2
       ) ;
bool operator < (
        ActionRef const & ap1,
        ActionRef const & ap2
       ) ;
bool operator == (
        ActionRef const & ap1,
        ActionRef const & ap2
       ) ;

LPP_NAMESPACE_END

#endif // ACTION_H
